import streamlit as st
import pandas as pd
import os
#import matplotlib.pyplot as plt
from pandasql import sqldf

import Config
Config.main()


##################
# 页面设置
st.set_page_config(page_title="单文件全量分析", page_icon="📊")
st.header("单文件全量分析")
st.markdown("* 使用pandas对单个文件进行分析")
st.markdown("* 可以使用sql语句进行分析")
st.write("*"*10)


##################
# 选项窗口
st.session_state.P02_datafile_info = st.text_input("请输入数据文件夹路径，或者数据文件路径：", value=st.session_state.P02_datafile_info)
if os.path.exists(st.session_state.P02_datafile_info) and os.path.isfile(st.session_state.P02_datafile_info):    
    datafile_path = st.session_state.P02_datafile_info
elif os.path.exists(st.session_state.P02_datafile_info):
    options = os.listdir(st.session_state.P03_datafile_info)
    for op in options:
        file_extension = os.path.splitext(op)[1]
        if file_extension not in ['.txt', '.csv', '.xls', '.xlsx']:
            options.remove(op)
    st.session_state.P02_datafile_name = st.selectbox("请选择数据文件：", options=options)
    datafile_path = os.path.join(st.session_state.P02_datafile_info, st.session_state.P02_datafile_name)
else:
    datafile_path = None
    st.error("请输入正确的数据文件信息")

st.session_state.P02_seperator = st.text_input("数据文件分隔符：", value=st.session_state.P02_seperator)
st.session_state.P02_encoding = st.text_input("数据文件编码：", value=st.session_state.P02_encoding)
st.session_state.P02_preview_rows = int(st.text_input("预览数据行数：", value=st.session_state.P02_preview_rows))
st.session_state.P02_firstline = st.checkbox("第一行是头信息，非数据", value=st.session_state.P02_firstline)

st.session_state.P02_headfile_info = st.text_input("请输入头文件路径，或者输入表头字符串，或者留空：", value=st.session_state.P02_headfile_info)
if st.session_state.P02_headfile_info is None or len(st.session_state.P02_headfile_info)==0:
    st.warning("未引入头文件，程序将认定数据文件自带头信息")
    headfile_info = None
elif(os.path.exists(st.session_state.P02_headfile_info)):
    st.session_state.P02_headfile_name = st.selectbox("请选择头文件【xlsx文件】：", options=os.listdir(st.session_state.P02_headfile_info))
    pass # 调用函数，读取头文件信息
    df = pd.read_excel(os.path.join(st.session_state.P02_headfile_info, st.session_state.P02_headfile_name))
    headfile_info = df.iloc[:,0].tolist()
    del df
    st.warning(f"使用文件 {st.session_state.P02_headfile_name} 作为头文件，头信息为 {headfile_info}")
else:
    #对字符串进行清洗，作为头信息
    st.session_state.P02_headfile_info = st.session_state.P02_headfile_info.replace('，', ',').replace('\t', ',').replace(' ', ',')
    headfile_info = st.session_state.P02_headfile_info.split(',')
    st.warning(f"头信息为 {headfile_info}")
st.divider()

##################
# 显示文件信息
st.write(f"当前文件夹路径： {st.session_state.P02_datafile_info}")
if datafile_path is not None:
    st.write(f"数据文件路径： {datafile_path}")
    st.write(f"数据文件大小： {round(os.path.getsize(datafile_path)/1024, 2)}KB / {round(os.path.getsize(datafile_path)/1024/1024, 2)}MB / {round(os.path.getsize(datafile_path)/1024/1024/1024, 2)}GB")
    dfname = os.path.splitext(os.path.basename(datafile_path))[0]
    st.write(f"数据表名： {dfname}")

#########################################################################################
##################
# 读取文件并预览
# 1. csv文件有表头并且是第一行，那么names和header都无需指定;
# 2. csv文件有表头、但表头不是第一行，可能从下面几行开始才是真正的表头和数据，这个时候指定header即可;
# 3. csv文件没有表头，全部是纯数据，那么我们可以通过names手动生成表头;
# 4. csv文件有表头、但是这个表头你不想用，这个时候同时指定names和header。先用header选出表头和数据，
#    然后再用names将表头替换掉，就等价于将数据读取进来之后再对列名进行rename；
df = None
names = headfile_info #默认值为None
header = 0 #默认值为infer
if st.session_state.P02_firstline:
    header = 0
else:
    header = None
nrows = st.session_state.P02_preview_rows
sep = st.session_state.P02_seperator
encoding = st.session_state.P02_encoding
if st.button("预览数据"):
    df = pd.read_csv(datafile_path, names=names, header=header, nrows=nrows, sep=sep, encoding=encoding)
    if df is None:
        st.write("文件读取失败")
    st.dataframe(df)
    del df

st.divider()

#########################################################################################

def write_excel(df, filepath):
    with pd.ExcelWriter(filepath, engine='openpyxl') as writer:
        df.to_excel(writer, sheet_name='Sheet1', index=False)

def write_csv(df, filepath, sep=',', encoding='utf-8'):
    df.to_csv(filepath, sep=sep, encoding=encoding, index=False)


##################
# 代码加载
code = ''
uploaded_file = st.file_uploader('请选择一个代码文件')
if uploaded_file is not None:
    from io import StringIO
    bytes_data = uploaded_file.getvalue()
    #st.write(bytes_data)
    stringio = StringIO(uploaded_file.getvalue().decode("utf-8"))
    #st.write(stringio)
    string_data = stringio.read()
    #st.write(string_data)    
    #exec(string_data)
    code = string_data


##################
# SQL输入框
st.session_state.P02_sql = st.text_area("SQL 语句：", value=f'select * from {dfname} limit 10;')
print(st.session_state.P02_sql)




# SQL 分析
# 为运行SQL查询定义可重复使用的函数
# query表示想要在Pandas数据帧上执行的SQL查询语句。它应该是一个包含有效SQL查询的字符串。
# globals()指定了查询中使用的数据帧所在的全局命名空间。
# sqldf函数将执行SQL查询，并返回一个Pandas数据帧，其中包含查询结果。
#run_query = lambda query: sqldf(query, globals()) #运行单句sql
def run_query(query):
    run = lambda query: sqldf(query, globals())
    query_list = query.split(';')
    query_list = [q for q in query_list if q.strip() != '']
    result = None
    for q in query_list:
        result = run(q)
    return result
sql = st.session_state.P02_sql

# 运行SQL查询
df = None
names = headfile_info #默认值为None
header = 0 #默认值为infer
if st.session_state.P02_firstline:
    header = 0
else:
    header = None
nrows = None
sep = st.session_state.P02_seperator
encoding = st.session_state.P02_encoding

if st.button("运行代码文件、SQL查询"):
    #df = pd.read_csv(datafile_path, names=names, header=header, nrows=nrows, sep=sep, encoding=encoding) 
    #exec(f'{dfname} = df')
    #del df
    exec(f'{dfname} = pd.read_csv(datafile_path, names=names, header=header, nrows=nrows, sep=sep, encoding=encoding)')
    exec(code)
    result = run_query(sql)
    st.dataframe(result)

if st.button("运行代码文件、SQL查询，并保存到excel文件"):
    exec(f'{dfname} = pd.read_csv(datafile_path, names=names, header=header, nrows=nrows, sep=sep, encoding=encoding)')    
    exec(code)
    result = run_query(sql)
    st.dataframe(result.head(100))
    write_excel(result, datafile_path+'_result.xlsx')
    st.success(f"保存成功:  {datafile_path}_result.xlsx")
